package com.ddzj.scaffold.handle;

import com.ddzj.scaffold.common.AjaxResultStatus;
import com.ddzj.scaffold.customexception.ServiceException;
import com.ddzj.scaffold.enums.AjaxResultStatusEnum;
import com.ddzj.scaffold.vo.AjaxResultVo;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.UnsatisfiedServletRequestParameterException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestClientException;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.util.List;
import java.util.StringJoiner;
import java.util.stream.Collectors;

@ControllerAdvice
public class ExceptionHandle {
    private static final Logger logger = LoggerFactory.getLogger(ExceptionHandle.class);

    /**
     * 应用到所有@RequestMapping注解方法，在其执行之前初始化数据绑定器
     * @param binder
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {}

    /**
     * 拦截捕捉自定义异常 MyException.class
     * @param ex
     * @return
     */
    @ResponseBody
    @ResponseStatus(value = HttpStatus.NOT_FOUND)
    @ExceptionHandler(value = ServiceException.class)
    public AjaxResultVo ajaxMyErrorHandler(ServiceException ex) {
        logger.debug("错误信息",ex);
        if(StringUtils.equals(ex.getCode(), AjaxResultStatus.ERROR_LOGIN_CODE)){
            return AjaxResultVo.error(AjaxResultStatusEnum.S_10001);
        }else{
            return AjaxResultVo.error(AjaxResultStatusEnum.S_ERROR, ex.getMessage());
        }
    }


    /**
     * 参数错误异常处理
     */
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(IllegalArgumentException.class)
    public AjaxResultVo illegalArgumentExceptionHandler(IllegalArgumentException e) {
        logger.debug("参数错误异常处理",e);
        return AjaxResultVo.error(AjaxResultStatusEnum.S_10004);
    }

    /**
     * 参数校验异常处理
     */
    @ResponseBody
    @ExceptionHandler(BindException.class)
    public AjaxResultVo bindExceptionHandler(BindException e) {
        List<FieldError> errors = e.getBindingResult().getFieldErrors();
        if(CollectionUtils.isNotEmpty(errors)) {
            return AjaxResultVo.error(AjaxResultStatusEnum.S_10004,
                    errors.stream().map(a -> {
                        return a.getField() + ":" + a.getDefaultMessage();
                    }).collect(Collectors.joining(",")));
        }
        return AjaxResultVo.error(AjaxResultStatusEnum.S_10004);
    }

    /**
     * 参数校验异常处理
     */
    @ResponseBody
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public AjaxResultVo methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        List<FieldError> errors = e.getBindingResult().getFieldErrors();
        if(CollectionUtils.isNotEmpty(errors)) {
            return AjaxResultVo.error(AjaxResultStatusEnum.S_10004, "参数校验失败-[" + errors.stream().map(a -> {
                return a.getField() + ":" + a.getDefaultMessage();
            }).collect(Collectors.joining(",")) + "]");
        }
        return AjaxResultVo.error(AjaxResultStatusEnum.S_10004);
    }

  /*  *//**
     * 不支持的请求方法
     *//*
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public AjaxResultVo httpRequestMethodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException e) {
        logger.debug("不支持的请求方法",e);
        //HttpStatus.METHOD_NOT_ALLOWED.value()
        return AjaxResultVo.error(AjaxResultStatusEnum.S_ERROR, "不支持的请求方法");
    }

    *//**
     * 请求类型错误
     *//*
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public AjaxResultVo httpMediaTypeNotSupportedExceptionHandler(HttpMediaTypeNotSupportedException e) {
        logger.debug("请求类型错误",e);
        //HttpStatus.UNSUPPORTED_MEDIA_TYPE.value()
        return AjaxResultVo.error(AjaxResultStatusEnum.S_ERROR, "请求类型错误");
    }

    *//**
     * 请求超时
     *//*
    @ExceptionHandler(AsyncRequestTimeoutException.class)
    public AjaxResultVo asyncRequestTimeoutExceptionHandler(AsyncRequestTimeoutException e) {
        logger.debug("请求类型错误",e);
        //HttpStatus.REQUEST_TIMEOUT.value()
        return AjaxResultVo.error(AjaxResultStatusEnum.S_ERROR, "请求超时");
    }

    *//**
     * 操作数据库出现异常
     *//*
    @ExceptionHandler(DataAccessException.class)
    public AjaxResultVo handleSqlException(DataAccessException e) {
        logger.debug("操作数据库出现异常", e);
        //HttpStatus.INTERNAL_SERVER_ERROR.value()
        return AjaxResultVo.error(AjaxResultStatusEnum.S_ERROR, "操作数据库出现异常");
    }

    *//**
     * 关联接口请求失败
     *//*
    @ExceptionHandler(RestClientException.class)
    public AjaxResultVo restClientExceptionHandler(RestClientException e) {
        logger.debug("关联接口请求失败", e);
        //HttpStatus.INTERNAL_SERVER_ERROR.value()
        return AjaxResultVo.error(AjaxResultStatusEnum.S_ERROR, "关联接口请求失败");
    }

    *//**
     * 请求参数缺失
     *//*
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public AjaxResultVo missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException e) {
        logger.debug("请求参数缺失", e);
        //HttpStatus.BAD_REQUEST.value()
        return AjaxResultVo.error(AjaxResultStatusEnum.S_ERROR, "请求参数" + e.getParameterName() + "缺失，数据类型：" + e.getParameterType());
    }

    *//**
     * 请求参数类型错误
     *//*
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public AjaxResultVo methodArgumentTypeMismatchExceptionHandler(MethodArgumentTypeMismatchException e) {
        logger.debug("请求参数类型错误", e);
        //HttpStatus.BAD_REQUEST.value()
        return AjaxResultVo.error(AjaxResultStatusEnum.S_ERROR, "请求参数类型错误");
    }

    *//**
     * 请求地址不存在
     *//*
    @ExceptionHandler(NoHandlerFoundException.class)
    public AjaxResultVo handleNoFoundException(NoHandlerFoundException e) {
        logger.debug("请求地址不存在", e);
        //HttpStatus.NOT_FOUND.value()
        return AjaxResultVo.error(AjaxResultStatusEnum.S_ERROR, "请求地址不存在");
    }

    *//**
     * 必须的请求参数不能为空
     *//*
    @ExceptionHandler(MissingServletRequestPartException.class)
    public AjaxResultVo missingServletRequestPartExceptionHandler(MissingServletRequestPartException e) {
        logger.debug("必须的请求参数不能为空", e);
        //HttpStatus.BAD_REQUEST.value()
        return AjaxResultVo.error(AjaxResultStatusEnum.S_ERROR, "必须的请求参数" + e.getRequestPartName() + "不能为空");
    }

    *//**
     * 请求参数解析异常
     *//*
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public AjaxResultVo httpMessageNotReadableExceptionHandler(HttpMessageNotReadableException e) {
        logger.debug("请求参数解析异常", e);
        //HttpStatus.BAD_REQUEST.value()
        return AjaxResultVo.error(AjaxResultStatusEnum.S_ERROR, "请求参数解析异常");
    }

    *//**
     * 请求参数不满足
     *//*
    @ExceptionHandler(UnsatisfiedServletRequestParameterException.class)
    public AjaxResultVo unsatisfiedServletRequestParameterExceptionHandler(UnsatisfiedServletRequestParameterException e) {
        String conditions = StringUtils.join(e.getParamConditions(), ",");
        StringJoiner params = new StringJoiner(",");
        e.getActualParams().forEach((k, v) -> params.add(k.concat("=").concat(ObjectUtils.nullSafeToString(v))));

        logger.debug("请求参数不满足", e);
        //HttpStatus.BAD_REQUEST.value()
        return AjaxResultVo.error(AjaxResultStatusEnum.S_ERROR, "请求参数异常：" + conditions + "|" + params);
    }*/

    /**
     * 全局异常捕捉处理
     * @param ex
     * @return
     */
    @ResponseBody
    @ResponseStatus(value = HttpStatus.NOT_FOUND)
    @ExceptionHandler(value = Exception.class)
    public AjaxResultVo ajaxErrorHandler(Exception ex) {
        logger.debug("错误信息",ex);
        return AjaxResultVo.error(AjaxResultStatusEnum.S_ERROR);
    }

}
